package ltd.hxya.novel.book.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import ltd.hxya.novel.book.dto.BookInfoRespDto;
import ltd.hxya.novel.book.dto.BookRankRespDto;
import ltd.hxya.novel.book.dto.HomeBookRespDto;
import ltd.hxya.novel.book.entity.Book;
import ltd.hxya.novel.book.entity.BookInfo;
import ltd.hxya.novel.book.entity.HomeBook;
import ltd.hxya.novel.book.mapper.BookInfoMapper;
import ltd.hxya.novel.book.service.BookInfoService;
import ltd.hxya.novel.book.utils.constant.CacheConsts;
import ltd.hxya.novel.book.utils.constant.DatabaseConsts;
import ltd.hxya.novel.common.utils.JsonUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.time.Duration;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 小说排行，前端显示处理
 * </p>
 *
 * @author ZWW
 * @since 2022-11-14
 */
@Service
public class BookInfoServiceImpl extends ServiceImpl<BookInfoMapper, BookInfo> implements BookInfoService {
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    /**
     * 列表排行榜处理
     * 大于0,并且取30个数据
     * @return 列表排行榜处理
     * @param bookInfoQueryWrapper
     */
    @Override
    public List<BookRankRespDto> listNewestRankBooks(QueryWrapper<BookInfo> bookInfoQueryWrapper) {
        String key = CacheConsts.BOOK_NEWEST_RANK_CACHE_NAME;
        // 1、从Redis中查看是否有缓存
        String sJson = stringRedisTemplate.opsForValue().get(key);
        // 2、判断是否为空
        if (!StringUtils.isEmpty(sJson)){
            // 3、直接返回处理
            List<BookRankRespDto> bookList = JSON.parseArray(sJson,BookRankRespDto.class);
            return bookList;
        }
        // 4、不存在就去数据库中查，然后存进去
        bookInfoQueryWrapper
                .gt(DatabaseConsts.BookTable.COLUMN_WORD_COUNT, 0)
                .last(DatabaseConsts.SqlEnum.LIMIT_30.getSql());
        List<BookRankRespDto> bookRankRespDtoList = listRankBooks(bookInfoQueryWrapper);
        String s = JsonUtils.objectToString(bookRankRespDtoList);
        stringRedisTemplate.opsForValue().set(key,s, Duration.ofHours(24));
        return bookRankRespDtoList;
    }

    /**
     * 小说点击榜的处理
     * @return 小说点击榜
     */
    @Override
    public List<BookRankRespDto> listVisitRankBooks() {
        String key = CacheConsts.BOOK_VISIT_RANK_CACHE_NAME;
        // 1、从Redis中查看是否有缓存
        String sJson = stringRedisTemplate.opsForValue().get(key);
        // 2、判断是否为空
        if (!StringUtils.isEmpty(sJson)){
            // 3、直接返回处理
            List<BookRankRespDto> bookList = JSON.parseArray(sJson,BookRankRespDto.class);
            return bookList;
        }
        // 4、不存在就去数据库中查，然后存进去
        QueryWrapper<BookInfo> bookInfoQueryWrapper = new QueryWrapper<>();
        bookInfoQueryWrapper.select(DatabaseConsts.BookInfo.DISINCT_COLUMNS).orderByDesc(DatabaseConsts.BookTable.COLUMN_VISIT_COUNT);
        List<BookRankRespDto> bookRankRespDtoList = listRankBooks(bookInfoQueryWrapper);
        // 转成JSON，然后存到Redis中去
        String s = JsonUtils.objectToString(bookRankRespDtoList);
        stringRedisTemplate.opsForValue().set(key,s,Duration.ofHours(24));
        return bookRankRespDtoList;
    }

    /**
     * 小说更新榜的处理
     * @return
     */
    @Override
    public List<BookRankRespDto> listUpdateRankBooks() {
        String key = CacheConsts.BOOK_UPDATE_RANK_CACHE_NAME;
        // 1、从Redis中查看是否有缓存
        String sJson = stringRedisTemplate.opsForValue().get(key);
        // 2、判断是否为空
        if (!StringUtils.isEmpty(sJson)){
            // 3、直接返回处理
            List<BookRankRespDto> bookList = JSON.parseArray(sJson,BookRankRespDto.class);
            return bookList;
        }
        // 4、不存在就去数据库中查，然后存进去
        QueryWrapper<BookInfo> bookInfoQueryWrapper = new QueryWrapper<>();
        bookInfoQueryWrapper
                .select(DatabaseConsts.BookInfo.DISINCT_COLUMNS)
                .gt(DatabaseConsts.BookTable.COLUMN_WORD_COUNT, 0)
                .orderByDesc(DatabaseConsts.CommonColumnEnum.UPDATE_TIME.getName());
        List<BookRankRespDto> bookRankRespDtoList = listRankBooks(bookInfoQueryWrapper);
        // 转成JSON，然后存到Redis中去
        String s = JsonUtils.objectToString(bookRankRespDtoList);
        stringRedisTemplate.opsForValue().set(key,s,Duration.ofHours(24));
        return bookRankRespDtoList;
    }

    @Override
    public List<BookInfo> getbookList(QueryWrapper<BookInfo> bookInfoQueryWrapper) {
        return baseMapper.selectList(bookInfoQueryWrapper);
    }

    /**
     * 查询基本信息
     * @param id
     * @return
     */
    @Override
    public BookInfo selectById(String id) {
        return baseMapper.selectById(id);
    }

    /**
     * 根据bookId，来查询一些信息
     * @param bookId
     * @return
     */
    @Override
    public BookInfoRespDto getBookInfo(String bookId) {
        // return cachePutBookInfo(id);
        return null;
    }

    @Override
    @Transactional
    public void saveBookInfo(List<Book> books,Integer type) {
        //删除原先的就
        QueryWrapper<BookInfo> bookInfoQueryWrapper = new QueryWrapper<>();
        bookInfoQueryWrapper.eq("type",type);
        baseMapper.delete(bookInfoQueryWrapper);
        List<BookInfo> collect = new ArrayList<>();
        for (Book book : books) {
            BookInfo bookInfo = new BookInfo();
            BeanUtils.copyProperties(book, bookInfo);
            bookInfo.setCategoryName(book.getCatName());
            bookInfo.setCategoryId(Long.valueOf(book.getCatId()));
            bookInfo.setLastChapterName(book.getLastIndexName());
            bookInfo.setId(IdWorker.getIdStr());
            bookInfo.setLastChapterId(book.getLastIndexId());
            bookInfo.setLastChapterUpdateTime(book.getLastIndexUpdateTime());
            bookInfo.setBookId(book.getId());
            bookInfo.setType(type);
            bookInfo.setScore(book.getScore());
            collect.add(bookInfo);
            if (collect.size()==10){
                break;
            }
        }
        this.saveBatch(collect);
    }

    @Override
    public List<HomeBookRespDto> listHomeBooks() {
        QueryWrapper<BookInfo> bookInfoQueryWrapper = new QueryWrapper<>();
        bookInfoQueryWrapper.orderByDesc("score");
        List<BookInfo> bookInfos = baseMapper.selectList(bookInfoQueryWrapper);
        List<HomeBookRespDto> collect = bookInfos.stream().map(bookInfo -> {
            HomeBookRespDto homeBookRespDto = new HomeBookRespDto();
            BeanUtils.copyProperties(bookInfo, homeBookRespDto);
            return homeBookRespDto;
        }).collect(Collectors.toList());
        return collect;
    }

    @Override
    public List<BookInfo> selectByType(Integer type) {
        QueryWrapper<BookInfo> bookInfoQueryWrapper = new QueryWrapper<>();
        bookInfoQueryWrapper.eq("type",type);
        List<BookInfo> bookInfos = baseMapper.selectList(bookInfoQueryWrapper);
        return bookInfos;
    }


    private List<BookRankRespDto> listRankBooks(QueryWrapper<BookInfo> bookInfoQueryWrapper) {
        bookInfoQueryWrapper
                .gt(DatabaseConsts.BookTable.COLUMN_WORD_COUNT, 0)
                .last(DatabaseConsts.SqlEnum.LIMIT_30.getSql());
        return baseMapper.selectList(bookInfoQueryWrapper).stream().map(v -> {
            BookRankRespDto respDto = new BookRankRespDto();
            respDto.setId(v.getId());
            respDto.setCategoryId(v.getCategoryId());
            respDto.setCategoryName(v.getCategoryName());
            respDto.setBookName(v.getBookName());
            respDto.setAuthorName(v.getAuthorName());
            respDto.setPicUrl(v.getPicUrl());
            respDto.setBookDesc(v.getBookDesc());
            respDto.setLastChapterName(v.getLastChapterName());
            respDto.setLastChapterUpdateTime(v.getLastChapterUpdateTime());
            respDto.setWordCount(v.getWordCount());
            return respDto;
        }).collect(Collectors.toList());
    }


}
